package com.junqson.je.recruit.service;

import com.alibaba.fastjson.JSON;
import com.junqson.je.common.UserHolder;
import com.junqson.je.common.exception.BizException;
import com.junqson.je.common.model.ApiResult;
import com.junqson.je.common.model.User;
import com.junqson.je.common.model.vo.SimpleUserInfo;
import com.junqson.je.common.util.AppUtil;
import com.junqson.je.recruit.model.ApplicationModel;
import com.junqson.je.recruit.model.JobModel;
import com.junqson.je.recruit.model.dto.MessageDTO;
import com.junqson.je.recruit.model.dto.ResumeDTO;
import com.junqson.je.recruit.model.enums.ApplyStatusEnum;
import com.junqson.je.recruit.model.vo.ApplicationVo;
import com.junqson.je.recruit.repo.ApplicationRepo;
import com.junqson.je.recruit.repo.JobRepo;
import com.junqson.je.recruit.util.PageUtil;
import com.junqson.je.recruit.util.UserInfoCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Descriptions 职位申请服务
 * @Company
 * @Author Junqson
 * @Date 2020/2/5 23:50
 * @Version 1.0
 */
@Service
@Slf4j
public class ApplicationService {

    @Autowired
    ApplicationRepo applicationRepo;

    @Autowired
    JobRepo jobRepo;

    @Autowired
    UserInfoCache userInfoCache;

    @Autowired
    ResumeService resumeService;

    @Autowired
    MsgService msgService;

    /**
     * 投递职位
     */
    public ApiResult applyJob(Integer jobId) {
        JobModel jobModel = jobRepo.findByJobId(jobId);
        if (jobModel == null) {
            log.warn("job not found, job id {}", jobId);
            return ApiResult.error("职位不存在");
        }
        if (jobModel.isClosed()) {
            return ApiResult.error("职位已关闭");
        }
        User user = UserHolder.get();
        int userId = user.getUserId();
        if (jobModel.getPublisherId() == userId) {
            return ApiResult.error("请勿投递自己的职位");
        }

        ApplicationModel application = applicationRepo.findByJobIdAndUserId(jobId, userId);
        if (application != null) {
            log.warn("重复投递, user id {} job id {}", userId, jobId);
            return ApiResult.error("请勿重复投递");
        }
        ResumeDTO resumeDTO = resumeService.getResume(userId);
        String resumeStr = JSON.toJSONString(resumeDTO);
        application = new ApplicationModel();
        application.setUserId(userId);
        application.setTitle(jobModel.getTitle());
        application.setJobId(jobModel.getJobId());
        application.setCompany(jobModel.getCompany());
        application.setApplyTime(new Date());
        application.setStatus(ApplyStatusEnum.已投递.name());
        application.setPublisherId(jobModel.getPublisherId());
        application.setResume(resumeStr);
        applicationRepo.save(application);

        String msgContent = String.format("用户[%s]刚刚投递了您的职位[%s]，快去看看吧!"
                , user.getUsername(), jobModel.getTitle());

        //发投递站内信给职位拥有者
        MessageDTO msg = MessageDTO.builder()
                .title("新投递通知")
                .content(msgContent)
                .toId(jobModel.getPublisherId())
                .build();

        msgService.sendMsg(msg);
        return ApiResult.success();
    }

    /**
     * 查看是否投递该职位
     */
    public boolean hasApplied(Integer jobId) {
        User user = UserHolder.get();
        return applicationRepo.findByJobIdAndUserId(jobId, user.getUserId()) != null;
    }

    /**
     * 查看个人投递记录
     */
    public List<ApplicationVo> pagePersonalApplications(Integer page, Integer size) {
        Sort sort =  Sort.by(Sort.Direction.DESC, "applyTime");
        Pageable pageable = PageUtil.getPageable(page, size, sort);
        User user = UserHolder.get();
        Page<ApplicationModel> models = applicationRepo.findByUserId(user.getUserId(), pageable);
        List<ApplicationModel> modelList = models.getContent();
        return modelList.stream().map(this::convertToApplicationVo).collect(Collectors.toList());
    }


    /**
     * 查看职位下的投递记录
     */
    public List<ApplicationVo> pageJobApplications(Integer jobId, Integer page, Integer size) {
        JobModel jobModel = jobRepo.findByJobId(jobId);
        if (jobModel == null) {
            throw new BizException("job not found, job id " + jobId.toString());
        }
        User user = UserHolder.get();
        if (user.getUserId() != jobModel.getPublisherId()) {
            throw new BizException("user" + user.getUserId() + " no auth get applications of job " + jobModel.getJobId());
        }
        Sort sort = Sort.by(Sort.Direction.DESC, "applyTime");
        Pageable pageable = PageUtil.getPageable(page, size, sort);
        Page<ApplicationModel> models = applicationRepo.findByJobId(jobId, pageable);
        return models.getContent().stream()
                .map(this::convertToApplicationVo)
                .map(this::assembleUserInfo)
                .collect(Collectors.toList());
    }


    /**
     * 查看发布的所有职位的投递记录
     */
    public List<ApplicationVo> pageAllJobApplications(Integer page, Integer size) {
        User user = UserHolder.get();
        int publiserId = user.getUserId();
        Sort sort = Sort.by(Sort.Direction.DESC, "applyTime");
        Pageable pageable = PageUtil.getPageable(page, size, sort);
        Page<ApplicationModel> models = applicationRepo.findByPublisherId(publiserId, pageable);
        return models.getContent().stream()
                .map(this::convertToApplicationVo)
                .map(this::assembleUserInfo)
                .collect(Collectors.toList());
    }


    /**
     * 完成投递过程
     */
    public void completeApplication(Integer applicationId) {
        ApplicationModel model = checkModifyApplicationAuth(applicationId);
        model.setStatus(ApplyStatusEnum.已完成.name());
        applicationRepo.save(model);

        String content = String.format("您投递的 %s 公司的 %s 职位流程已完成，请尽快查看!"
                , model.getCompany(), model.getTitle());
        MessageDTO dto = MessageDTO.builder()
                .title("职位投递记录状态变化通知")
                .content(content)
                .toId(model.getUserId())
                .build();
        msgService.sendMsg(dto);
    }


    /**
     * 拒绝该投递
     */
    public void rejectApplication(Integer applicationId) {
        ApplicationModel model = checkModifyApplicationAuth(applicationId);
// TODO: 状态校验逻辑考虑
        //        ApplyStatusEnum currentStatus = ApplyStatusEnum.valueOf(model.getStatus());
//        if (currentStatus != ApplyStatusEnum.已投递) {
//            throw new BizException("该申请已完成或已回绝");
//        }
        model.setStatus(ApplyStatusEnum.已回绝.name());
        applicationRepo.save(model);


        String content = String.format("您投递的 %s 公司的 %s 职位已被拒绝，请尽快查看!"
                , model.getCompany(), model.getTitle());
        MessageDTO dto = MessageDTO.builder()
                .title("职位投递记录状态变化通知")
                .content(content)
                .toId(model.getUserId())
                .build();
        msgService.sendMsg(dto);
    }

    /**
     * 查看简历
     */
    public ResumeDTO getResumeOfApplication(Integer applicationId) {
        User user = UserHolder.get();
        int userId = user.getUserId();
        String resumeStr = applicationRepo.getResumeByPublisherIdAndApplicationId(userId, applicationId);
        ResumeDTO resume = JSON.parseObject(resumeStr, ResumeDTO.class);
        return resume;
    }


    /**
     * 检查是否具有修改此投递记录状态的权限，成功则返回投递记录model
     * @param applicationId
     */
    public ApplicationModel checkModifyApplicationAuth(Integer applicationId) {
        User user = UserHolder.get();
        int userId = user.getUserId();
        ApplicationModel applicationModel = applicationRepo.findByApplicationId(applicationId);
        if (applicationModel == null) {
            log.error("application not found, id {}", applicationId);
            throw new BizException("投递记录不存在");
        }
        if (userId != applicationModel.getPublisherId()) {
            throw new BizException("无权操作此投递记录");
        }
        return applicationModel;
    }


    public ApplicationVo convertToApplicationVo(ApplicationModel model) {
        ApplicationVo vo = new ApplicationVo();
        AppUtil.copyPropertiesIgnoreNull(model, vo);
        return vo;
    }

    public ApplicationVo assembleUserInfo(ApplicationVo vo) {
        int userId = vo.getUserId();
        SimpleUserInfo userInfo = userInfoCache.getUserInfo(userId);
        vo.setUserInfo(userInfo);
        return vo;
    }
}
